/*
 * Copyright © 2016-2019 The Thingsboard Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import './trip-animation-widget.scss';
import template from "./trip-animation-widget.tpl.html";
import TbOpenStreetMap from '../openstreet-map';
import L from 'leaflet';
import tinycolor from "tinycolor2";
import {fillPatternWithActions, isNumber, padValue, processPattern} from "../widget-utils";

(function () {
	// save these original methods before they are overwritten
	var proto_initIcon = L.Marker.prototype._initIcon;
	var proto_setPos = L.Marker.prototype._setPos;

	var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');

	L.Marker.addInitHook(function () {
		var iconOptions = this.options.icon && this.options.icon.options;
		var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;
		if (iconAnchor) {
			iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');
		}
		this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom';
		this.options.rotationAngle = this.options.rotationAngle || 0;

		// Ensure marker keeps rotated during dragging
		this.on('drag', function (e) {
			e.target._applyRotation();
		});
	});

	L.Marker.include({
		_initIcon: function () {
			proto_initIcon.call(this);
		},

		_setPos: function (pos) {
			proto_setPos.call(this, pos);
			this._applyRotation();
		},

		_applyRotation: function () {
			if (this.options.rotationAngle) {
				this._icon.style[L.DomUtil.TRANSFORM + 'Origin'] = this.options.rotationOrigin;

				if (oldIE) {
					// for IE 9, use the 2D rotation
					this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
				} else {
					// for modern browsers, prefer the 3D accelerated version
					let rotation = ' rotateZ(' + this.options.rotationAngle + 'deg)';
					if (!this._icon.style[L.DomUtil.TRANSFORM].includes(rotation)) {
						this._icon.style[L.DomUtil.TRANSFORM] += rotation;
					}
				}
			}
		},

		setRotationAngle: function (angle) {
			this.options.rotationAngle = angle;
			this.update();
			return this;
		},

		setRotationOrigin: function (origin) {
			this.options.rotationOrigin = origin;
			this.update();
			return this;
		}
	});
})();


export default angular.module('thingsboard.widgets.tripAnimation', [])
	.directive('tripAnimation', tripAnimationWidget)
	.filter('tripAnimation', function ($filter) {
		return function (label) {
			label = label.toString();

			let translateSelector = "widgets.tripAnimation." + label;
			let translation = $filter('translate')(translateSelector);

			if (translation !== translateSelector) {
				return translation;
			}

			return label;
		}
	})
	.name;


/*@ngInject*/
function tripAnimationWidget() {
	return {
		restrict: "E",
		scope: true,
		bindToController: {
			ctx: '=',
			self: '='
		},
		controller: tripAnimationController,
		controllerAs: 'vm',
		templateUrl: template
	};
}

/*@ngInject*/
function tripAnimationController($document, $scope, $http, $timeout, $filter, $sce) {
	let vm = this;

	vm.initBounds = true;

	vm.markers = [];
	vm.index = 0;
	vm.dsIndex = 0;
	vm.minTime = 0;
	vm.maxTime = 0;
	vm.isPlaying = false;
	vm.trackingLine = {
		"type": "FeatureCollection",
		features: []
	};
	vm.speeds = [1, 5, 10, 25];
	vm.speed = 1;
	vm.trips = [];
	vm.activeTripIndex = 0;

	vm.showHideTooltip = showHideTooltip;
	vm.recalculateTrips = recalculateTrips;

	$scope.$watch('vm.ctx', function () {
		if (vm.ctx) {
			vm.utils = vm.ctx.$scope.$injector.get('utils');
			vm.settings = vm.ctx.settings;
			vm.widgetConfig = vm.ctx.widgetConfig;
			vm.data = vm.ctx.data;
			vm.datasources = vm.ctx.datasources;
			configureStaticSettings();
			initialize();
			initializeCallbacks();
		}
	});


	function initializeCallbacks() {
		vm.self.onDataUpdated = function () {
			createUpdatePath(true);
		};

		vm.self.onResize = function () {
			resize();
		};

		vm.self.typeParameters = function () {
			return {
				maxDatasources: 1, // Maximum allowed datasources for this widget, -1 - unlimited
				maxDataKeys: -1 //Maximum allowed data keys for this widget, -1 - unlimited
			}
		};
		return true;
	}


	function resize() {
		if (vm.map) {
			vm.map.invalidateSize();
		}
	}

	function initCallback() {
		//createUpdatePath();
		//resize();
	}

	vm.playMove = function (play) {
		if (play && vm.isPlaying) return;
		if (play || vm.isPlaying) vm.isPlaying = true;
		if (vm.isPlaying) {
            moveInc(1);
			vm.timeout = $timeout(function () {
				vm.playMove();
			}, 1000 / vm.speed)
		}
	};

    vm.moveNext = function () {
        vm.stopPlay();
        moveInc(1);
    }

    vm.movePrev = function () {
        vm.stopPlay();
        moveInc(-1);
    }

    vm.moveStart = function () {
        vm.stopPlay();
        moveToIndex(vm.minTime);
    }

    vm.moveEnd = function () {
        vm.stopPlay();
        moveToIndex(vm.maxTime);
    }

	vm.stopPlay = function () {
        if (vm.isPlaying) {
            vm.isPlaying = false;
            $timeout.cancel(vm.timeout);
        }
	};

    function moveInc(inc) {
        let newIndex = vm.index + inc;
        moveToIndex(newIndex);
    }

    function moveToIndex(newIndex) {
        if (newIndex > vm.maxTime || newIndex < vm.minTime) return;
        vm.index = newIndex;
        recalculateTrips();
    }

	function recalculateTrips() {
		vm.trips.forEach(function (value) {
			moveMarker(value);
		})
	}

	function findAngle(lat1, lng1, lat2, lng2) {
		let angle = Math.atan2(0, 0) - Math.atan2(lat2 - lat1, lng2 - lng1);
		angle = angle * 180 / Math.PI;
		return parseInt(angle.toFixed(2));
	}

	function initialize() {
		$scope.currentDate = $filter('date')(0, "yyyy.MM.dd HH:mm:ss");

		vm.self.actionSources = [vm.searchAction];
		vm.endpoint = vm.ctx.settings.endpointUrl;
		$scope.title = vm.ctx.widgetConfig.title;
		vm.utils = vm.self.ctx.$scope.$injector.get('utils');

		vm.showTimestamp = vm.settings.showTimestamp !== false;
		vm.ctx.$element = angular.element("#trip-animation-map", vm.ctx.$container);
		vm.defaultZoomLevel = 2;
		if (vm.ctx.settings.defaultZoomLevel) {
			if (vm.ctx.settings.defaultZoomLevel > 0 && vm.ctx.settings.defaultZoomLevel < 21) {
				vm.defaultZoomLevel = Math.floor(vm.ctx.settings.defaultZoomLevel);
			}
		}
		vm.dontFitMapBounds = vm.ctx.settings.fitMapBounds === false;
		vm.map = new TbOpenStreetMap(vm.ctx.$element, vm.utils, initCallback, vm.defaultZoomLevel, vm.dontFitMapBounds, null, vm.staticSettings.mapProvider);
		vm.map.bounds = vm.map.createBounds();
		vm.map.invalidateSize(true);
		vm.map.bounds = vm.map.createBounds();

		vm.tooltipActionsMap = {};
		var descriptors = vm.ctx.actionsApi.getActionDescriptors('tooltipAction');
		descriptors.forEach(function (descriptor) {
			if (descriptor) vm.tooltipActionsMap[descriptor.name] = descriptor;
		});
	}

	function configureStaticSettings() {
		let staticSettings = {};
		vm.staticSettings = staticSettings;
		//Calculate General Settings
        staticSettings.buttonColor = tinycolor(vm.widgetConfig.color).setAlpha(0.54).toRgbString();
        staticSettings.disabledButtonColor = tinycolor(vm.widgetConfig.color).setAlpha(0.3).toRgbString();
		staticSettings.mapProvider = vm.ctx.settings.mapProvider || "OpenStreetMap.Mapnik";
		staticSettings.latKeyName = vm.ctx.settings.latKeyName || "latitude";
		staticSettings.lngKeyName = vm.ctx.settings.lngKeyName || "longitude";
		staticSettings.rotationAngle = vm.ctx.settings.rotationAngle || 0;
		staticSettings.displayTooltip = vm.ctx.settings.showTooltip || false;
		staticSettings.defaultZoomLevel = vm.ctx.settings.defaultZoomLevel || true;
		staticSettings.showTooltip = false;
		staticSettings.label = vm.ctx.settings.label || "${entityName}";
		staticSettings.useLabelFunction = vm.ctx.settings.useLabelFunction || false;
		staticSettings.showLabel = vm.ctx.settings.showLabel || false;
		staticSettings.useTooltipFunction = vm.ctx.settings.useTooltipFunction || false;
		staticSettings.tooltipPattern = vm.ctx.settings.tooltipPattern || "<span style=\"font-size: 26px; color: #666; font-weight: bold;\">${entityName}</span>\n" +
            "<br/>\n" +
            "<span style=\"font-size: 12px; color: #666; font-weight: bold;\">Time:</span><span style=\"font-size: 12px;\"> ${formattedTs}</span>\n" +
            "<span style=\"font-size: 12px; color: #666; font-weight: bold;\">Latitude:</span> ${latitude:7}\n" +
            "<span style=\"font-size: 12px; color: #666; font-weight: bold;\">Longitude:</span> ${longitude:7}";
		staticSettings.tooltipOpacity = angular.isNumber(vm.ctx.settings.tooltipOpacity) ? vm.ctx.settings.tooltipOpacity : 1;
		staticSettings.tooltipColor = vm.ctx.settings.tooltipColor ? tinycolor(vm.ctx.settings.tooltipColor).toRgbString() : "#ffffff";
		staticSettings.tooltipFontColor = vm.ctx.settings.tooltipFontColor ? tinycolor(vm.ctx.settings.tooltipFontColor).toRgbString() : "#000000";
		staticSettings.pathColor = vm.ctx.settings.color ? tinycolor(vm.ctx.settings.color).toHexString() : "#ff6300";
		staticSettings.pathWeight = vm.ctx.settings.strokeWeight || 1;
		staticSettings.pathOpacity = vm.ctx.settings.strokeOpacity || 1;
		staticSettings.usePathColorFunction = vm.ctx.settings.useColorFunction || false;
		staticSettings.showPoints = vm.ctx.settings.showPoints || false;
		staticSettings.pointSize = vm.ctx.settings.pointSize || 1;
		staticSettings.markerImageSize = vm.ctx.settings.markerImageSize || 20;
		staticSettings.useMarkerImageFunction = vm.ctx.settings.useMarkerImageFunction || false;
		staticSettings.pointColor = vm.ctx.settings.pointColor ? tinycolor(vm.ctx.settings.pointColor).toHexString() : "#ff6300";
		staticSettings.markerImages = vm.ctx.settings.markerImages || [];
		staticSettings.icon = L.icon({
			iconUrl: "",
			iconSize: [30, 30],
			iconAnchor: [15, 15]
		});
		if (angular.isDefined(vm.ctx.settings.markerImage)) {
			staticSettings.icon = L.icon({
				iconUrl: vm.ctx.settings.markerImage,
				iconSize: [staticSettings.markerImageSize, staticSettings.markerImageSize],
				iconAnchor: [(staticSettings.markerImageSize / 2), (staticSettings.markerImageSize / 2)]
			})
		}

		if (staticSettings.usePathColorFunction && angular.isDefined(vm.ctx.settings.colorFunction)) {
			staticSettings.colorFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.colorFunction);
		}

		if (staticSettings.useLabelFunction && angular.isDefined(vm.ctx.settings.labelFunction)) {
			staticSettings.labelFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.labelFunction);
		}

		if (staticSettings.useTooltipFunction && angular.isDefined(vm.ctx.settings.tooltipFunction)) {
			staticSettings.tooltipFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.tooltipFunction);
		}

		if (staticSettings.useMarkerImageFunction && angular.isDefined(vm.ctx.settings.markerImageFunction)) {
			staticSettings.markerImageFunction = new Function('data, images, dsData, dsIndex', vm.ctx.settings.markerImageFunction);
		}

		if (!staticSettings.useMarkerImageFunction &&
			angular.isDefined(vm.ctx.settings.markerImage) &&
			vm.ctx.settings.markerImage.length > 0) {
			staticSettings.useMarkerImage = true;
			let url = vm.ctx.settings.markerImage;
			let size = staticSettings.markerImageSize || 20;
			staticSettings.currentImage = {
				url: url,
				size: size
			};
			vm.utils.loadImageAspect(staticSettings.currentImage.url).then(
				(aspect) => {
					if (aspect) {
						let width;
						let height;
						if (aspect > 1) {
							width = staticSettings.currentImage.size;
							height = staticSettings.currentImage.size / aspect;
						} else {
							width = staticSettings.currentImage.size * aspect;
							height = staticSettings.currentImage.size;
						}
						staticSettings.icon = L.icon({
							iconUrl: staticSettings.currentImage.url,
							iconSize: [width, height],
							iconAnchor: [width / 2, height / 2]
						});
					}
					if (vm.trips) {
						vm.trips.forEach(function (trip) {
							if (trip.marker) {
								trip.marker.setIcon(staticSettings.icon);
							}
						});
					}
				}
			)
		}
	}

	function configureTripSettings(trip, index, apply) {
		trip.settings = {};
		trip.settings.color = calculateColor(trip);
		trip.settings.strokeWeight = vm.staticSettings.pathWeight;
		trip.settings.strokeOpacity = vm.staticSettings.pathOpacity;
		trip.settings.pointColor = vm.staticSettings.pointColor;
		trip.settings.pointSize = vm.staticSettings.pointSize;
		trip.settings.icon = calculateIcon(trip);
		if (apply) {
            $timeout(() => {
                trip.settings.labelText = calculateLabel(trip);
                trip.settings.tooltipText = $sce.trustAsHtml(calculateTooltip(trip));
            },0,true);
        } else {
            trip.settings.labelText = calculateLabel(trip);
            trip.settings.tooltipText = $sce.trustAsHtml(calculateTooltip(trip));
        }
	}

	function calculateLabel(trip) {
		let label = '';
		if (vm.staticSettings.showLabel) {
			let labelReplaceInfo;
			let labelText = vm.staticSettings.label;
			if (vm.staticSettings.useLabelFunction && angular.isDefined(vm.staticSettings.labelFunction)) {
				try {
					labelText = vm.staticSettings.labelFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dsIndex);
				} catch (e) {
					labelText = null;
				}
			}
			labelText = vm.utils.createLabelFromDatasource(trip.dataSource, labelText);
			labelReplaceInfo = processPattern(labelText, vm.ctx.datasources, trip.dSIndex);
			label = fillPattern(labelText, labelReplaceInfo, trip.timeRange[vm.index]);
			if (vm.staticSettings.useLabelFunction && angular.isDefined(vm.staticSettings.labelFunction)) {
				try {
					labelText = vm.staticSettings.labelFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
				} catch (e) {
					labelText = null;
				}
			}
		}
		return label;
	}

	function calculateTooltip(trip) {
		let tooltip = '';
		if (vm.staticSettings.displayTooltip) {
			let tooltipReplaceInfo;
			let tooltipText = vm.staticSettings.tooltipPattern;
			if (vm.staticSettings.useTooltipFunction && angular.isDefined(vm.staticSettings.tooltipFunction)) {
				try {
					tooltipText = vm.staticSettings.tooltipFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
				} catch (e) {
					tooltipText = null;
				}
			}
			tooltipText = vm.utils.createLabelFromDatasource(trip.dataSource, tooltipText);
			tooltipReplaceInfo = processPattern(tooltipText, vm.ctx.datasources, trip.dSIndex);
			tooltip = fillPattern(tooltipText, tooltipReplaceInfo, trip.timeRange[vm.index]);
			tooltip = fillPatternWithActions(tooltip, 'onTooltipAction', null);

		}
		return tooltip;
	}

	function calculateColor(trip) {
		let color = vm.staticSettings.pathColor;
		let colorFn;
		if (vm.staticSettings.usePathColorFunction && angular.isDefined(vm.staticSettings.colorFunction)) {
			try {
				colorFn = vm.staticSettings.colorFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
			} catch (e) {
				colorFn = null;
			}
		}
		if (colorFn && colorFn !== color && trip.polyline) {
			trip.polyline.setStyle({color: colorFn});
		}
		return colorFn || color;
	}

	function calculateIcon(trip) {
		let icon = vm.staticSettings.icon;
		if (vm.staticSettings.useMarkerImageFunction && angular.isDefined(vm.staticSettings.markerImageFunction)) {
			let rawIcon;
			try {
				rawIcon = vm.staticSettings.markerImageFunction(vm.ctx.data, vm.staticSettings.markerImages, trip.timeRange[vm.index], trip.dSIndex);
			} catch (e) {
				rawIcon = null;
			}
			if (rawIcon) {
				vm.utils.loadImageAspect(rawIcon).then(
					(aspect) => {
						if (aspect) {
							let width;
							let height;
							if (aspect > 1) {
								width = rawIcon.size;
								height = rawIcon.size / aspect;
							} else {
								width = rawIcon.size * aspect;
								height = rawIcon.size;
							}
							icon = L.icon({
								iconUrl: rawIcon,
								iconSize: [width, height],
								iconAnchor: [width / 2, height / 2]
							});
						}
						if (trip.marker) {
							trip.marker.setIcon(icon);
						}
					}
				)
			}
		}
		return icon;
	}

	function createUpdatePath(apply) {
		if (vm.trips && vm.map) {
			vm.trips.forEach(function (trip) {
				if (trip.marker) {
					trip.marker.remove();
					delete trip.marker;
				}
				if (trip.polyline) {
					trip.polyline.remove();
					delete trip.polyline;
				}
				if (trip.points && trip.points.length) {
					trip.points.forEach(function (point) {
						point.remove();
					});
					delete trip.points;
				}
			});
			vm.initBounds = true;
		}
		let normalizedTimeRange = createNormalizedTime(vm.data, 1000);
		createNormalizedTrips(normalizedTimeRange, vm.datasources);
		createTripsOnMap(apply);
		if (vm.initBounds && !vm.initTrips) {
			vm.trips.forEach(function (trip) {
				vm.map.extendBounds(vm.map.bounds, trip.polyline);
				vm.initBounds = !vm.datasources.every(
					function (ds) {
						return ds.dataReceived === true;
					});
				vm.initTrips = vm.trips.every(function (trip) {
					return angular.isDefined(trip.marker) && angular.isDefined(trip.polyline);
				});
			});

			vm.map.fitBounds(vm.map.bounds);
		}
	}

	function fillPattern(pattern, replaceInfo, currentNormalizedValue) {
		let text = angular.copy(pattern);
		let reg = /\$\{([^\}]*)\}/g;
		if (replaceInfo) {
			for (let v = 0; v < replaceInfo.variables.length; v++) {
				let variableInfo = replaceInfo.variables[v];
				let label = reg.exec(pattern)[1].split(":")[0];
				let txtVal = '';
				if (label.length > -1 && angular.isDefined(currentNormalizedValue[label])) {
					let varData = currentNormalizedValue[label];
					if (isNumber(varData)) {
						txtVal = padValue(varData, variableInfo.valDec, 0);
					} else {
						txtVal = varData;
					}
				}
				text = text.split(variableInfo.variable).join(txtVal);
			}
		}
		return text;
	}

	function createNormalizedTime(data, step) {
		if (!step) step = 1000;
		let max_time = null;
		let min_time = null;
		let normalizedArray = [];
		if (data && data.length > 0) {
			vm.data.forEach(function (data) {
				if (data.data.length > 0) {
					data.data.forEach(function (sData) {
						if (max_time === null) {
							max_time = sData[0];
						} else if (max_time < sData[0]) {
							max_time = sData[0]
						}
						if (min_time === null) {
							min_time = sData[0];
						} else if (min_time > sData[0]) {
							min_time = sData[0];
						}
					})
				}
			});
			for (let i = min_time; i < max_time; i += step) {
				normalizedArray.push({ts: i, formattedTs: $filter('date')(i, 'medium')});

			}
			if (normalizedArray[normalizedArray.length - 1] && normalizedArray[normalizedArray.length - 1].ts !== max_time) {
                normalizedArray.push({ts: max_time, formattedTs: $filter('date')(max_time, 'medium')});
            }
		}
		vm.maxTime = normalizedArray.length - 1;
		vm.minTime = vm.maxTime > 1 ? 1 : 0;
		if (vm.index < vm.minTime) {
            vm.index = vm.minTime;
        } else if (vm.index > vm.maxTime) {
            vm.index = vm.maxTime;
        }
		return normalizedArray;
	}

	function createNormalizedTrips(timeRange, dataSources) {
		vm.trips = [];
		if (timeRange && timeRange.length > 0 && dataSources && dataSources.length > 0 && vm.data && vm.data.length > 0) {
			dataSources.forEach(function (dS, index) {
				vm.trips.push({
					dataSource: dS,
					dSIndex: index,
					timeRange: angular.copy(timeRange)
				})
			});

			vm.data.forEach(function (data) {
				let ds = data.datasource;
				let tripIndex = vm.trips.findIndex(function (el) {
					return el.dataSource.entityId === ds.entityId;
				});

				if (tripIndex > -1) {
					createNormalizedValue(data.data, data.dataKey.label, vm.trips[tripIndex].timeRange);
				}
			})
		}

		createNormalizedLatLngs();
	}

	function createNormalizedValue(dataArray, dataKey, timeRangeArray) {
		timeRangeArray.forEach(function (timeStamp) {
			let targetTDiff = null;
			let value = null;
			for (let i = 0; i < dataArray.length; i++) {
				let tDiff = dataArray[i][0] - timeStamp.ts;
				if (targetTDiff === null || (tDiff <= 0 && targetTDiff < tDiff)) {
					targetTDiff = tDiff;
					value = dataArray[i][1];

				}
			}
			if (value !== null) timeStamp[dataKey] = value;
		});
	}

	function createNormalizedLatLngs() {
		vm.trips.forEach(function (el) {
			el.latLngs = [];
			el.timeRange.forEach(function (data) {
				let lat = data[vm.staticSettings.latKeyName];
				let lng = data[vm.staticSettings.lngKeyName];
				if (lat && lng && vm.map) {
					data.latLng = vm.map.createLatLng(lat, lng);
				}
				el.latLngs.push(data.latLng);
			});
			addAngleForTrip(el);
		})
	}

	function addAngleForTrip(trip) {
		if (trip.timeRange && trip.timeRange.length > 0) {
			trip.timeRange.forEach(function (point, index) {
				let nextPoint, prevPoint;
				nextPoint = index === (trip.timeRange.length - 1) ? trip.timeRange[index] : trip.timeRange[index + 1];
				prevPoint = index === 0 ? trip.timeRange[0] : trip.timeRange[index - 1];
				let nextLatLng = {
                    lat: nextPoint[vm.staticSettings.latKeyName],
                    lng: nextPoint[vm.staticSettings.lngKeyName]
                };
                let prevLatLng = {
                    lat: prevPoint[vm.staticSettings.latKeyName],
                    lng: prevPoint[vm.staticSettings.lngKeyName]
                };
                if (nextLatLng.lat === prevLatLng.lat && nextLatLng.lng === prevLatLng.lng) {
                    if (angular.isNumber(prevPoint.h)) {
                        point.h = prevPoint.h;
                    } else {
                        point.h = vm.staticSettings.rotationAngle;
                    }
                } else {
                    point.h = findAngle(prevLatLng.lat, prevLatLng.lng, nextLatLng.lat, nextLatLng.lng);
                    point.h += vm.staticSettings.rotationAngle;
                }
			});
		}
	}

	function createTripsOnMap(apply) {
		if (vm.trips.length > 0) {
			vm.trips.forEach(function (trip) {
				if (trip.timeRange.length > 0 && trip.latLngs.every(el => angular.isDefined(el))) {
					configureTripSettings(trip, vm.index, apply);
					if (vm.staticSettings.showPoints) {
						trip.points = [];
						trip.latLngs.forEach(function (latLng) {
							let point = L.circleMarker(latLng, {
								color: trip.settings.pointColor,
								radius: trip.settings.pointSize
							}).addTo(vm.map.map);
							trip.points.push(point);
						});
					}

					if (angular.isUndefined(trip.marker)) {
						trip.polyline = vm.map.createPolyline(trip.latLngs, trip.settings);
					}

					if (trip.timeRange && trip.timeRange.length && angular.isUndefined(trip.marker)) {
						trip.marker = L.marker(trip.timeRange[vm.index].latLng);
						trip.marker.setZIndexOffset(1000);
						trip.marker.setIcon(vm.staticSettings.icon);
						trip.marker.setRotationOrigin('center center');
                        trip.marker.on('click', function () {
                            showHideTooltip(trip);
                        });
						trip.marker.addTo(vm.map.map);
						moveMarker(trip);
					}
				}
			});
		}
	}

	function moveMarker(trip) {
		if (angular.isDefined(trip.marker)) {
			trip.markerAngleIsSet = true;
			trip.marker.setLatLng(trip.timeRange[vm.index].latLng);
			trip.marker.setRotationAngle(trip.timeRange[vm.index].h);
			trip.marker.update();
		} else {
			if (trip.timeRange && trip.timeRange.length) {
				trip.marker = L.marker(trip.timeRange[vm.index].latLng);
				trip.marker.setZIndexOffset(1000);
				trip.marker.setIcon(vm.staticSettings.icon);
				trip.marker.setRotationOrigin('center center');
                trip.marker.on('click', function () {
                    showHideTooltip(trip);
                });
				trip.marker.addTo(vm.map.map);
				trip.marker.update();
			}

		}
		configureTripSettings(trip);
	}


	function showHideTooltip(trip) {
		if (vm.staticSettings.displayTooltip)  {
			if (vm.staticSettings.showTooltip && trip && vm.activeTripIndex !== trip.dSIndex) {
				vm.staticSettings.showTooltip = true;
			} else {
				vm.staticSettings.showTooltip = !vm.staticSettings.showTooltip;
			}
		}
		if (trip && vm.activeTripIndex !== trip.dSIndex) vm.activeTripIndex = trip.dSIndex;
	}
}